#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string>
#include <process.h>
#include <iostream>
#include "robot_mkdata.h"
#include "robot_order.h"
#include "readpair.h"
#include "def.h"
#include "guard.h"
#include "log.h"
#include "pnl.h"

using namespace std;

cmutex criticalvrlock_;
int MAXTRADEDNUM=2;
vector<realorder> criticalvr;
int traded_share_number = 0;
int SHAREPERSLOT = 100;
bool DISABLETRADE = false;
double MOVEPERTRADE = 1.0;
////////////////////////////////////////////////////
unsigned int __stdcall Thread_MKData(void* p_){
  robot_mkdata* p = reinterpret_cast<robot_mkdata*>(p_);
  p->reqAccountUpdates();
  p->_state = MK_REQCONTRACT;
  while(p->isConnected()){
    p->processMessages();
  }
  p->CancelMkData();
  return 0;
}

unsigned int /*__stdcall*/ Thread_CheckBandFile(void* p_){
  char* fpath = (char*)(p_);
  char szBuf[MAX_PATH];
  HANDLE hFile = CreateFileA(fpath, GENERIC_READ, FILE_SHARE_READ, NULL,OPEN_EXISTING, 0, NULL);
  if(hFile == INVALID_HANDLE_VALUE){
    printf("CreateFile failed with %d\n", GetLastError());
    return 0;
  }
  FILETIME ftCreate={0}, ftAccess={0}, ftWrite={0};
  if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
    return 0;
  FILETIME ftWrite2={0};
  while (true){
    Sleep(2000);
    if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite2))
      return 0;
    if (ftWrite.dwHighDateTime!=ftWrite2.dwHighDateTime || ftWrite.dwLowDateTime!=ftWrite2.dwLowDateTime){
      printf("reload band file!\n");
    }
  }
  CloseHandle(hFile);
  return 0;
}

void Thread_Order(robot_order* p){
  while(p->isConnected()){
    p->processMessages();
    if(!criticalvr.empty() && p->_criticalvr.empty()){
      cguard gd(criticalvrlock_);
      p->_criticalvr = criticalvr;
      p->_state = ST_PLACEORDER;
      criticalvr.clear();
    }
  }
}

void printusage();

////////////////////////////////////////////////////
int main(int argc, char** argv){
  //Thread_CheckBandFile("C:\\_src\\twintower\\twintower\\analysis\\twintowers-2014-03-25.lst");
  if (argc!=7){
    printusage();
    return -1;
  }
  const char* host = argv[1];
  const char* spreadfile = argv[2];
  unsigned int port = 7496;
  bool cn = false;
  MAXTRADEDNUM = atoi(argv[3]);
  int clientId = atoi(argv[4]);
  DISABLETRADE = strcmp(argv[5],"1");
  MOVEPERTRADE = ::atof(argv[6]);

  vector<spread> spread_band= getspreadinfo(spreadfile);
  if(spread_band.empty()){
    TTPrint("BAND FILE is WRONG!\n");
    return -1;
  }

  ibaccount::R();

  vector<cdiff*> pdiffs;
  vector<robot_mkdata*> mkdatavector;
  for (size_t i=0;i<spread_band.size();++i){
    cdiff* ppd = new cdiff();
    pdiffs.push_back(ppd);

    spread *band = &spread_band[i];
    TTPrint("master:%s, slave:%s\n", band->master.c_str(), band->slave.c_str());

    // master
    robot_mkdata *master=new robot_mkdata();
    mkdatavector.push_back(master);

    cn = master->connect(host, port, clientId++);
    if (cn && master->isConnected()){
      master->setsymbol(band->master);
      master->ismaster = true;
      master->pdiff=ppd;
      ppd->mc = &master->contract;
      master->spread_band = band;
      ::_beginthreadex( NULL, 0, &Thread_MKData, master, 0, NULL);
    }else{
      TTPrint("[%s(%d)]Cannot connect to TWS!\n",__FUNCTION__,__LINE__);
      return -1;
    }

    //////////////////////////////////////////////////////////////////////////
    robot_mkdata *slave=new robot_mkdata();
    mkdatavector.push_back(slave);

    cn = slave->connect(host, port, clientId++);
    if (cn && slave->isConnected()){
      slave->setsymbol(band->slave);
      slave->ismaster = false;
      slave->pdiff = ppd;
      ppd->sc = &slave->contract;
      slave->spread_band = band;
      ::_beginthreadex( NULL, 0, &Thread_MKData, slave, 0, NULL);
    }else{
      TTPrint("Cannot connect to TWS!\n");
      return -1;
    }
  }

  // for sending order only
  robot_order traderob;
  cn = traderob.connect(host,port,clientId++);
  if (cn && traderob.isConnected()){
    traderob.reqAccountUpdates();
    Thread_Order(&traderob);
  }
  return 0;
}

//send limit order
void tradespread_limitorder(Contract* pmster,double masterprice,
                            Contract* pslave, double slaveprice,
                            int size, bool islong)
{
  for (vector<realorder>::iterator i=criticalvr.begin();i!=criticalvr.end();++i){
    if(i->cmaster.symbol==pmster->symbol){
      return;
    }
  }// prevent repeated order!!!!

  Order order_master;
  order_master.totalQuantity = size;
  order_master.action = islong?"BUY":"SELL";
  order_master.orderType = "LMT";
  order_master.lmtPrice = masterprice;

  Order order_slave;
  order_slave.totalQuantity = size;
  order_slave.action = islong?"SELL":"BUY";
  order_slave.orderType = "LMT";
  order_slave.lmtPrice = slaveprice;

  realorder r1;
  r1.cmaster=*pmster;
  r1.omaster=order_master;
  r1.cslave=*pslave;
  r1.oslave=order_slave;

  criticalvr.push_back(r1);
}

void liquidate_limitorder(Contract* pmster,double mbid, double mask,
                          Contract* pslave, double sbid, double sask,
                          int masterposition, int slaveposition)
{
  for (vector<realorder>::iterator i=criticalvr.begin();i!=criticalvr.end();++i){
    if(i->cmaster.symbol==pmster->symbol){
      return;
    }
  }// prevent repeated order!!!!

  Order order_master;
  Order order_slave;

  if (masterposition!=0){
    order_master.totalQuantity = abs(masterposition);
    order_master.action = (masterposition<0)?"BUY":"SELL";
    order_master.orderType = "LMT";
    order_master.lmtPrice = (masterposition<0)?mask:mbid;
  }

  if(slaveposition!=0){
    order_slave.totalQuantity = abs(slaveposition);
    order_slave.action = (slaveposition<0)?"BUY":"SELL";
    order_slave.orderType = "LMT";
    order_slave.lmtPrice = (slaveposition<0)?sask:sbid;
  }

  realorder r1;
  r1.cmaster=*pmster;
  r1.omaster=order_master;
  r1.cslave=*pslave;
  r1.oslave=order_slave;

  criticalvr.push_back(r1);
}

pair<string,string> GetExchangeCurrency(const string& symbol){
    bool HKStock = ('0'<=symbol[0] && symbol[0]<='9');
    string exchange= HKStock?"SEHK":"SMART";
    string currency= HKStock?"HKD":"USD";
    return pair<string,string>(exchange,currency);
}

void printusage(){
  printf("Please run the program like:\n"
    "twintowers 127.0.0.1 x.csv 10(MAXTRADEDNUM) 0(ClientID) 1(1-enable trade;0-disable trade) 1.0(MOVEPERTRADE)\n");
}